package com.sisgh.jefdv1.cmd.command.has.multi;

import com.sisgh.jefdv1.cmd.command.has.ArgsCommand;
import com.sisgh.jefdv1.cmd.command.has.arg.argument.Argument;
import com.sisgh.jefdv1.exception.cmd.InvalidCommandException;
import com.sisgh.jefdv1.exception.cmd.arg.InvalidArgumentException;
import com.sisgh.jefdv1.util.StringUtils;

import java.util.*;

public abstract class MultiArgsCommand extends ArgsCommand {

    protected Map<String, Argument> args;

    protected abstract boolean isArgName(String arg);

    private Map<String, List<String>> formatArgs(List<String> parts) {
        Map<String, List<String>> formatArgs = new HashMap<>();

        String argName = null;
        List<String> values = new ArrayList<>();
        for (String part : parts) {
            if (isArgName(part)) {
                if (argName != null) {
                    formatArgs.put(argName, values);
                    values.clear();
                }
                argName = part;
            } else {
                values.add(part);
            }
        }
        if (argName != null) {
            formatArgs.put(argName, values);
        }

        return formatArgs;
    }

    protected void doProcessArgs(Argument arg, Map<String, List<String>> args) {
        for (String argName : args.keySet()) {
            if (arg.matches(argName)) {
                List<String> values = args.get(argName);
                arg.values(values);
                args.remove(argName);
                return ;
            }
        }
    }

    @Override
    protected void processArgs(List<String> parts) throws InvalidArgumentException {
        int size = parts.size();
        if (size < 2) {
            throw new InvalidCommandException("至少2个参数");
        }

        Map<String, List<String>> fmtArgs = formatArgs(parts);

        for (Argument arg : args.values()) {
            doProcessArgs(arg, fmtArgs);

            if (!arg.hasValues() && arg.valueRequired()) {
                String msg = StringUtils.format("参数[{}/{}]需要参数值", arg.longName(), arg.shortName());
                throw new InvalidArgumentException(msg);
            }
        }
    }

    public MultiArgsCommand(Argument[] args) {
        this.args = new HashMap<>();

        for (Argument arg : args) {
            this.args.put(arg.longName(), arg);
        }
    }
}
